package mybaits;

import annotion.Param;
import annotion.Table;

import java.io.File;
import java.lang.reflect.*;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class MySqlSessionFactory {
    private static final String JDBCURL = "jdbc:mysql://localhost:3306/demo";
    private static final String DBUSER = "root";
    private static final String PASSWORD = "root";

    @SuppressWarnings("all") // 忽略警告
    public <T> T getMapper(Class<T> mapperClass){
        //使用JDK动态代理
        //三个参数 classLoader--类加载器, interface--接口数组, invocationHandler--调用处理器
        return (T) Proxy.newProxyInstance(this.getClass().getClassLoader(), new Class[]{mapperClass}, new MapperInvocationHandler()
//                {
//             invoke方法参数，proxy, method, args
//            @Override
//            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//                if(method.getReturnType() == String.class){
//                    return "hello world";
//                }else if(method.getReturnType() == int.class){
//                    return 1;
//                }else{
//                    return null;
//                }
//            }
//        }
        );

    }

    static class MapperInvocationHandler implements InvocationHandler{
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //这里只做 select，调用Hashcode会需要返回int，但现在返回Null,会报错
            if(method.getName().startsWith("select")){
                return invokeSelect(proxy, method, args);
            }
            return null;
        }
        private Object invokeSelect(Object proxy, Method method, Object[] args) throws Throwable{
            String sql = createSelectSql(method);//拼接sql
           //List<String> selcetCols = getSelectCols(method.getReturnType());
           // String sql = "select " + String.join(",", selcetCols)"* from user where id = ?";
            try (Connection connection = DriverManager.getConnection(JDBCURL, DBUSER, PASSWORD);
                 PreparedStatement preparedStatement = connection.prepareStatement(sql)) {
                for(int i = 0; i < args.length; i++){
                    Object arg = args[i];
                    if(arg instanceof Integer){
                        preparedStatement.setInt(i + 1, (Integer) arg);
                    }else if(arg instanceof String){
                        preparedStatement.setString(i + 1, (String) arg);
                    }
                }
                //这行代码执行SQL查询并返回结果集
                ResultSet rs = preparedStatement.executeQuery();
                //判断返回类型是否为List
                if(List.class.isAssignableFrom(method.getReturnType())){
                    // 收集所有结果
                    List<Object> results = new ArrayList<>();
                    while (rs.next()) {
                        //获取LIst的泛型Class
                        results.add(parseResult(method.getReturnType(), rs));
                        return results;
                    }
                }else{
                    if(rs.next()){
                        return parseResult(method.getReturnType(), rs);
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }


        private Object parseResult(Class<?> returnType, ResultSet rs) throws Exception{
            //Userclass对象
            //获取无参构造，通过构造获取新对象
            /*通过反射获取返回类型的无参构造器，创建新实例
            获取该类的所有字段
            遍历字段，根据字段类型从ResultSet中获取对应数据
            使用反射设置对象字段值
            返回填充完数据的对象*/
            Constructor<?> constructor = returnType.getConstructor();
            Object result = constructor.newInstance();
            Field[] fields = returnType.getDeclaredFields();
            for(Field field : fields){
                Object column = null;
                String name = field.getName();
                if(field.getType() == String.class){
                    column = rs.getString(name);
                }else if(field.getType() == int.class){
                    column = rs.getInt(name);
                }
                field.setAccessible( true);
                field.set(result, column);
            }
            return result;
        }

        private String createSelectSql(Method method) {
            //List<String> selcetCols = getSelectCols(method.getReturnType());
            // String sql = "select * from user where id = ?";
            StringBuilder sql = new StringBuilder();
            sql.append("select ");
            List<String> selctCols = getSelectCols(method.getReturnType());
            sql.append(String.join(", ", selctCols));
            sql.append(" from ");
            //获取表,自定义注解后获取
            sql.append(getSelectTableName(method.getReturnType()));
            //获取条件
            sql.append(" where ");
            //获取条件字段,通过参数来获取，拼接查询条件，也需要注解定义条件
            sql.append(getSelectwhere(method));
            System.out.println( sql.toString());
            return sql.toString();
        }

        private String getSelectwhere(Method method) {
            //return "id = ?";
            //拿到方法参数信息,下面展示了拿取id这一个字段的，代码优雅点拿stream流来操作
//            Parameter[] parameters = method.getParameters();
//            for (Parameter parameter : parameters) {
//                Param param = parameter.getAnnotation(Param.class);
//                String column = param.value();
//                String condition = column + " = ?";
//            }
            return Arrays.stream(method.getParameters()).map((parameter)->{
                Param param = parameter.getAnnotation(Param.class);
                String column = param.value();
                return column + " = ?";
            }).collect(Collectors.joining(" and "));

        }

        private String getSelectTableName(Class<?> returnType) {
            Table table = returnType.getAnnotation(Table.class);
            if(table == null){
                throw new RuntimeException("返回值无法确定");
            }
            return table.tableName();
        }

        private List<String> getSelectCols(Class<?> returnType) {
            //获取字段
//            获取指定类的所有声明字段
//            将字段数组转换为流
//            映射获取每个字段的名称
//            收集为字符串列表返回
            Field[] declaredFiles = returnType.getDeclaredFields();
            return Arrays.stream(declaredFiles).map(Field::getName).toList();
        }
    }
}
